package com.example.jasonrpc.server;

import com.example.jasonrpc.codec.Decoder;
import com.example.jasonrpc.codec.Encoder;
import com.example.jasonrpc.proto.Request;
import com.example.jasonrpc.proto.Response;
import com.example.jasonrpc.server.simple.ServiceInstance;
import com.example.jasonrpc.server.simple.ServiceInvoker;
import com.example.jasonrpc.server.simple.ServiceManager;
import com.example.jasonrpc.transport.RequestHandler;
import com.example.jasonrpc.transport.TransportServer;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

public abstract class RpcServerAbstract {
    protected final Logger log = LoggerFactory.getLogger(this.getClass());
    protected TransportServer net;
    protected Encoder encoder;
    protected Decoder decoder;
    protected ServiceManager manager;
    protected ServiceInvoker invoker;

    protected RequestHandler handler = (request, response) -> {
        Response resp = new Response();
        //从client请求中读取序列化的数据，将其反序列化后，
        //调用实际的方法，最后将结果序列化后写入到响应中返回
        try {
            byte[] bytes = IOUtils.readFully(request, request.available());
            Request req = decoder.decode(bytes, Request.class);
            log.info("get request: " + req);
            ServiceInstance serviceInstance = manager.lookUp(req);
            Object ret = invoker.invoke(serviceInstance, req);
            resp.setData(ret);
        } catch (Exception e) {
            log.warn(e.getMessage(), e);
            resp.setCode(1);
            resp.setMessage("RpcServer got error: " + e.getClass().getName() + ", " + e.getMessage());
        } finally {
            try {
                byte[] bytes = encoder.encode(resp);
                response.write(bytes);
                log.info("response to client: " + resp.getData());
            } catch (IOException e) {
                log.warn(e.getMessage(), e);
            }
        }
    };

    public <T> void register(Class<T> interfaceClass, T bean) {
        manager.register(interfaceClass, bean);
    }

    public abstract void start();

    public abstract void stop();
}
